﻿using IoTAdapter;
using IoTAdapter.BaseCore;
using IoTAdapter.BaseCore.Enums;
using IoTAdapter.Clients.Modbus;
using IoTAdapter.Core.Interface;
using SQLitePCL;
using System.ComponentModel;
using System.Drawing;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Threading;

namespace JunionRobotTaskManager.Models.ElevatorControl
{
    /// <summary>
    ///通讯协议参考"鲁邦通EC6200标准 MODBUS TCP 电梯控制协议V1.0"；目前只支持单车调用
    /// </summary>
    public class Elevator
    {
        private CancellationTokenSource _cts;
        public Action<string, object[]> Logger;

        /// <summary>
        /// 唯一标识
        /// </summary>
        public string Id { get; set; }

        /// <summary>
        /// 电梯控制流
        /// </summary>
        public ControlStream ControlStream { get; private set; }

        #region client
        /// <summary>
        /// 服务器IP
        /// </summary>
        public string IP { get; set; }

        /// <summary>
        /// 服务器端口
        /// </summary>
        public int Port { get; set; } = 502;

        /// <summary>
        /// 服务器站号
        /// </summary>
        public int Station { get; set; } = 1;

        /// <summary>
        /// modbus地址是否从1开始
        /// </summary>
        public bool ModbusIsStartWithOne { get; set; }

        /// <summary>
        /// 通讯协议
        /// </summary>
        public EthernetDeviceVersion CommunicationProtocol { get; set; } = EthernetDeviceVersion.ModbusTcp;

        /// <summary>
        /// 通讯接口
        /// </summary>
        public IReadWrite CommunicationInterface { get; private set; }

        /// <summary>
        /// 通信是否连接
        /// </summary>
        public bool IsConnected { get; private set; }
        #endregion

        /// <summary>
        /// 使用电梯的AGV
        /// </summary>
        public string RobotId { get; set; }

        /// <summary>
        /// 上次按键时间
        /// </summary>
        public DateTime? LastKeyTime { get; private set; }

        /// <summary>
        /// 呼叫电梯间隔时间
        /// </summary>
        public int CallSpanTime { get; set; }

        /// <summary>
        /// 最低层
        /// </summary>
        public int LowestFloor { get; private set; }

        /// <summary>
        /// 最高层
        /// </summary>
        public int HightestFloor { get; set; }

        #region Status
        /// <summary>
        /// 当前楼层
        /// </summary>
        public short CurrentFloor { get; private set; }

        /// <summary>
        /// 电梯状态
        /// </summary>
        public ElevatorStatus Status { get; private set; }

        /// <summary>
        /// 运行状态
        /// </summary>
        public RunningState RunningState { get; private set; }

        /// <summary>
        /// 门状态
        /// </summary>
        public DoorStatus DoorStatus { get; private set; }
        #endregion

        public Elevator(string ip, int lowestFloor, int hightestFloor, int callSpanTime)
        {
            IP = ip;
            CommunicationInterface = IoTClientFactory.CreateClientEthernetDevice(CommunicationProtocol, ip, Port, (byte)Station, 10000, ModbusIsStartWithOne, DataFormat.ABCD);
            LowestFloor = lowestFloor;
            if (hightestFloor <= 0)
            {
                throw new Exception("hightest floor set error");
            }
            HightestFloor = hightestFloor;
            CallSpanTime = callSpanTime;
            ControlStream = new ControlStream(this);
        }

        public bool Connect()
        {
            _cts?.Dispose();
            _cts = new CancellationTokenSource();
            var result = CommunicationInterface.Connect();
            if (result.IsSucceed)
            {
                Logger?.Invoke($"elevator({IP}) connect success", null);
            }
            return result.IsSucceed;
        }

        public bool Disconnet()
        {
            var result = CommunicationInterface.Close();
            if (result.IsSucceed)
            {
                Logger?.Invoke($"elevator({IP}) disconnect success", null);
            }
            _cts.Cancel();
            return result.IsSucceed;
        }

        /// <summary>
        /// 获取实时信息；长时间不给服务器发消息，服务器会关闭连接
        /// </summary>
        /// <returns></returns>
        public void Monitor()
        {
            var factory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
            factory.StartNew(async () =>
            {
                while (!_cts.IsCancellationRequested)
                {
                    try
                    {
                        IsConnected = CommunicationInterface.IsConnected;
                        if (IsConnected)
                        {
                            Logger?.Invoke(ToString(), null);   
                            await GetStatusAsync();
                            if (ControlStream.InExecution || DateTime.Now.Second % 5 == 0)
                            {
                                Logger?.Invoke(ToString(), null);
                            }
                        }
                        else
                        {
                            Logger?.Invoke($"elevator({IP}) alwready disconncted, now ready connect", null);
                            Connect();
                        }
                    }
                    catch(Exception ex)
                    {
                        Logger?.Invoke($"monitor error:{ex}", null);
                    }
                    await Task.Delay(1000);
                }
            });
        }

        /// <summary>
        /// 获取电梯本身状态
        /// </summary>
        /// <returns></returns>
        public async Task GetStatusAsync()
        {
            if (IsConnected)
            {
                CurrentFloor = (await CommunicationInterface.ReadInt16Async("0")).Value;
                //值定义与枚举基值定义一一对应
                var values = (await CommunicationInterface.ReadUInt16Async("1", 6)).Value;
                DoorStatus = (DoorStatus)values[0];
                Status = (ElevatorStatus)values[2];
                RunningState = (RunningState)values[3];
            }
        }

        /// <summary>
        /// 呼叫电梯并开门
        /// </summary>
        /// <returns></returns>
        public async Task<bool> CallAndOpenAsync(int floor)
        {
            if (!IsConnected || Status != ElevatorStatus.Available)
            {
                Logger?.Invoke("**********************1111111******************",null);
                return false;
            }
            else
            {
                if (CurrentFloor != floor)
                {
                    Logger?.Invoke("**********************2222222222222******************", null);

                    LastKeyTime = LastKeyTime == null ? DateTime.Now : LastKeyTime;
                    if ((DateTime.Now - LastKeyTime.Value).TotalSeconds >= CallSpanTime)
                    {
                        //var result = (await CommunicationInterface.WriteAsync("100", (ushort)1));
                        Logger?.Invoke("*********************3333333333******************", null);

                        var result = await (CommunicationInterface as IModbusClient).WriteSingleHoldRegisterAsync("100", (short)floor);
                        Logger?.Invoke($"request:{result.Requst}; response:{result.Response}", null);

                        if (result.IsSucceed)
                        {
                            LastKeyTime = DateTime.Now;
                            return true;
                        }
                    }
                }
                else
                {
                    switch (DoorStatus)
                    {
                        case DoorStatus.Open: return true;
                        case DoorStatus.Close: return await OpenDoorAsync();
                        default: throw new Exception("none");
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 开门
        /// </summary>
        /// <returns></returns>
        public async Task<bool> OpenDoorAsync()
        {
            if (!IsConnected || Status != ElevatorStatus.Available)
            {
                return false;
            }
            else
            {
                switch (DoorStatus)
                {
                    case DoorStatus.Open: return true;
                    case DoorStatus.Close:
                        if (RunningState == RunningState.Motionless)
                        {
                            var result = (await (CommunicationInterface as IModbusClient).WriteSingleHoldRegisterAsync("101", (short)1));
                            Logger?.Invoke($"request:{result.Requst}; response:{result.Response}", null);

                            return result.IsSucceed;
                        }
                        else
                        {
                            return false;
                        }
                    default: throw new Exception("none");
                }
            }
        }

        /// <summary>
        /// 关门
        /// </summary>
        /// <returns></returns>
        public async Task<bool> CloseDoorAsync()
        {
            if (!IsConnected || Status != ElevatorStatus.Available)
            {
                return false;
            }
            else
            {
                switch (DoorStatus)
                {
                    //梯控厂商用功能码10关门有bug；实际数据类型为ushort
                    case DoorStatus.Open: return (await (CommunicationInterface as IModbusClient).WriteSingleHoldRegisterAsync("101", (short)2)).IsSucceed;
                    case DoorStatus.Close: return true;
                    default: throw new Exception("none");
                }
            }
        }

        /// <summary>
        /// 复位使用状态
        /// </summary>
        public void Reset()
        {
            RobotId = null;
            LastKeyTime = null;
        }

        public override string ToString()
        {
            var sb = new StringBuilder();
            foreach (var property in GetType().GetProperties())
            {
                if (property.Name != nameof(CommunicationInterface) && property.Name != nameof(CommunicationProtocol) && property.Name != nameof(ControlStream))
                {
                    if (property.GetValue(this) != null)
                    {
                        sb.Append(property.Name + ":" + property.GetValue(this).ToString() + "; ");
                    }
                }
            }
            return sb.ToString();
        }
    }

    public enum ElevatorStatus : ushort
    {
        [Description("未知")]
        None = 0,
        [Description("可用")]
        Available,
        [Description("不可用")]
        NotAvailable
    }

    public enum RunningState : ushort
    {
        [Description("未知")]
        None,
        [Description("静止")]
        Motionless,
        [Description("上行")]
        Up,
        [Description("下行")]
        Down
    }

    public enum DoorStatus : ushort
    {
        [Description("未知")]
        None,
        [Description("打开")]
        Open,
        [Description("关闭")]
        Close
    }
}
